package com.wang.transfer.util.thread;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 线程池的五种实现<br>
 * 1、newCachedThreadPool
 * 创建一个线程池，如果线程池中的线程数量过大，它可以有效的回收多余的线程，如果线程数不足，那么它可以创建新的线程
 * 2、newFixedThreadPool
 * 这种方式可以指定线程池中的线程数
 * 3、newScheduledThreadPool
 * 该线程池支持定时，以及周期性的任务执行，我们可以延迟任务的执行时间，也可以设置一个周期性的时间让任务重复执行
 * 4、newSingleThreadExecutor
 * 这是一个单线程池，至始至终都由一个线程来执行
 * 5、ThreadPoolTaskExecutor
 * 这个类是spring包下的，是spring给我们提供的线程池类
 * 线程池的使用
 * submit和execute方法的区别：
 * execute只能提交Runnable类型的任务，无返回值；
 * submit既能提交Runnable类型的任务，返回值为null,也能提交Callable类型的任务，返回值为Future类型
 */
@Component
public class ThreadPoolDemo {

    @Resource(name = "taskExecutor")
    private ThreadPoolTaskExecutor taskExecutor;

    public static void main(String[] args) {
        ThreadPoolDemo demo = new ThreadPoolDemo();
//        demo.haveReturnThreadPool();
//        demo.threadPoolRunJobs();
//        demo.asyncThread();
        demo.springThreadPool();
    }

    /**
     * 创建线程池，执行有返回值的任务
     */
    public void haveReturnThreadPool() {
        // 创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        // 创建多个有返回值的任务
        List<Future<String>> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Callable<String> myCallable = new MyCallable(i + "");
            // 执行任务并获取Future对象
            Future<String> submit = pool.submit(myCallable);
            list.add(submit);
        }
        // 关闭线程池
        pool.shutdown();
        // 获取所有并发任务的运行结果
        for (Future<String> f : list) {
            try {
                System.out.println("res:" + f.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 创建线程池执行多任务
     */
    public void threadPoolRunJobs() {
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        boolean tag = true;
        for (int i = 1; i <= 20; i++) {
            threadPool.submit(new MyRunnable(i));
        }
        // 关闭线程池
        threadPool.shutdown();
        while (tag) {
            try {
                Thread.sleep(1000);
                if (threadPool.isTerminated()) {
                    tag = false;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("线程池执行完毕！");
    }

    /**
     * 创建异步线程执行任务
     */
    public void asyncThread() {
        Thread thread = new Thread(new AsyncThread());
        thread.start();
    }

    /**
     * 使用spring提供的ThreadPoolTaskExecutor包
     */
    public void springThreadPool() {
        taskExecutor.submit(new ServerStarter());
    }
}

class MyCallable implements Callable<String> {

    private final String msg;

    public MyCallable(String msg) {
        this.msg = msg;
    }

    @Override
    public String call() throws Exception {
        return this.msg + ",有返回值的任务必须继承Callable接口";
    }
}

class MyRunnable implements Runnable {

    private final Integer threadId;

    public MyRunnable(Integer threadId) {
        this.threadId = threadId;
    }

    @Override
    public void run() {
        System.out.println("线程" + threadId + " is running...");
    }
}

class AsyncThread extends Thread {

    @Override
    public void run() {
        ThreadPoolDemo threadPoolDemo = new ThreadPoolDemo();
        threadPoolDemo.threadPoolRunJobs();
        System.out.println("asyncThread 执行：" + Thread.currentThread().getName());
    }
}

